assume cs: codesg, ds: data, es: table

codesg segment
start:
    mov ax, data
    mov ds, ax
    mov es, ax

    mov cx, 21  ; 设置循环计数，总共21年的数据
    mov si, 0   ; si 用于指向 data 段中的字符串数组的起始位置
    mov di, 0   ; di 用于指向 table 段中的字符串的起始位置

next_year:
    ; 输出年份
    mov ah, [ds:si]  ; 将年份字符串的地址加载到 ah 中
    mov [es:di], ah
    add di, 2      ; 移动到下一个字符位置，因为我们已经输出了一个字节的数据长度

    ; 输出收入
    mov eax, [ds:si+2]  ; 将收入的双字（dd）加载到 eax 中
    call print_number   ; 调用打印数字的子程序

    ; 输出雇员人数
    mov ax, [ds:si+10]  ; 将雇员人数的字（dw）加载到 ax 中
    call print_number   ; 调用打印数字的子程序

    ; 计算人均收入
    xor edx, edx        ; 清零 edx 用于存储结果
    mov ebx, [ds:si+10]  ; 将雇员人数加载到 ebx 中
    idiv ebx            ; eax / ebx，结果在 eax 中，余数在 edx 中

    ; 输出人均收入
    call print_number   ; 调用打印数字的子程序

    ; 移动到下一个数据项
    add si, 12        ; 移动到下一年的字符串和数据
    add di, 10        ; 移动到下一个字符串的起始位置

    loop next_year     ; 循环直到 cx 为 0

    ; 结束程序
    mov ax, 4c00h
    int 21h
codesg ends

; 打印数字的子程序
print_number proc
    pusha              ; 保存所有寄存器
    mov bx, 10          ; 设置除数为 10
    lea sp, [sp-6]      ; 在栈上分配空间存储数字

convert_loop:
    xchg ax, [sp]      ; 将数字从 ax 移动到栈中
    xor dx, dx          ; 清除 dx
    idiv bx              ; 除以 10，结果在 ax 中，余数在 dx 中
    push dx             ; 将余数（数字）压入栈中
    cmp ax, 0           ; 检查是否完成
    jnz convert_loop    ; 如果 ax 不为 0，继续循环

print_loop:
    pop ax              ; 弹出一个数字
    add al, '0'         ; 将数字转换为 ASCII
    stosb              ; 存储数字字符到 es:di 指向的位置
    loop print_loop     ; 继续循环直到栈为空

    popa                ; 恢复所有寄存器
    ret
print_number endp

data segment
    ; 数据定义同上
data ends

table segment
    ; 表定义同上
table ends
